package com.pansoft.xbrl.xbrljson.config;

import com.pansoft.xbrl.xbrljson.config.model.JsonConfigItem;
import com.pansoft.xbrl.xbrljson.config.model.XbrlJsonConfig;
import com.pansoft.xbrl.xbrljson.model.Entity;
import com.pansoft.xbrl.xbrljson.model.SchemaRef;
import com.pansoft.xbrl.xbrljson.model.Unit;
import com.pansoft.xbrl.xbrljson.model.Xbrl;
import com.pansoft.xbrl.xbrljson.util.StringUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * 配置文件读取器
 * @author coolmayi
 * @create 2021/9/3
 */
public class XbrlJsonConfigReader {


    private File configFile ;


    public XbrlJsonConfigReader() {

    }
    /**
     * 读取配置文件
     * @param fileUrl
     * @return
     */
    public XbrlJsonConfig reafFile(URL fileUrl) {

        XbrlJsonConfig configObject = null;
        Document document = null;
        try {
            SAXReader saxReader = new SAXReader();
            document = saxReader.read(fileUrl);
            Element rootNode = document.getRootElement();

            String rootName = rootNode.getName();
            if (!"xbrlJson".equals(rootName)) {
                // 不是有效的配置文件
                return configObject;
            }

            String configId = rootNode.attributeValue("id");
            String configName = rootNode.attributeValue("name");
            configObject = new XbrlJsonConfig();
            configObject.setConfigId(configId);
            configObject.setConfigName(configName);


            List<Element> childList = rootNode.elements();

            if (childList == null || childList.size() == 0) {
                return configObject;
            }

            for (Element childItem : childList) {
                this.readConfigNode(childItem, configObject);
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return configObject;
    }

    /**
     * 读取配置文件
     * @param configFile
     * @return
     */
    public XbrlJsonConfig reafFile(File configFile) {
    	
    	try {
			return reafFile(configFile.toURI().toURL());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
    	return null;
    }

    /**
     * 读取配置节点
     * @param childItem
     * @param configObject
     */
    private void readConfigNode(Element childItem, XbrlJsonConfig configObject) {

        if (childItem == null || configObject == null) {
            return ;
        }

        String nodeName = childItem.getName();

        if("instanceDoc".equals(nodeName)){
            this.readInstanceDocNode(childItem, configObject);
        } else if("objectDefine".equals(nodeName)){
            this.readObjectDefineNode(childItem, configObject);
        }else if("jsonObject".equals(nodeName)){
            this.readJsonObjectNode(childItem, configObject);
        }

//        switch (nodeName) {
//            case "instanceDoc":
//                this.readInstanceDocNode(childItem, configObject);
//                break;
//            case "objectDefine":
//                this.readObjectDefineNode(childItem, configObject);
//                break;
//            case "jsonObject":
//                this.readJsonObjectNode(childItem, configObject);
//                break;
//            default:
//        }


    }

    /**
     * 读取实例文档全局配置
     * @param node
     * @param configObject
     */
    private void readInstanceDocNode(Element node, XbrlJsonConfig configObject) {

        List<Element> childList = node.elements();
        if (childList == null || childList.size() == 0) {
            return ;
        }

        for (Element childNode : childList) {

            String childNodeName = childNode.getName();


            if("nameSpaceRef".equals(childNodeName)){
                this.readNameSpaceNode(childNode, configObject);
            } else if ("SchemaLocationRef".equals(childNodeName)){
                this.readSchemaLocationNode(childNode, configObject);
            } else if ("UnitRef".equals(childNodeName)){
                this.readUnitNode(childNode, configObject);
            } else if ("SchemaRef".equals(childNodeName)){
                this.readSchemaRefNode(childNode, configObject);
            } else if ("EntityRef".equals(childNodeName)){
                this.readEntityRefNode(childNode, configObject);
            } else if ("ContextInstantRef".equals(childNodeName)){
                this.readContextInstantRefNode(childNode, configObject);
            }

//            switch (childNodeName) {
//                case "nameSpaceRef":
//                    this.readNameSpaceNode(childNode, configObject);
//                    break;
//                case "SchemaLocationRef":
//                    this.readSchemaLocationNode(childNode, configObject);
//                    break;
//                case "UnitRef":
//                    this.readUnitNode(childNode, configObject);
//                    break;
//                case "SchemaRef":
//                    this.readSchemaRefNode(childNode, configObject);
//                    break;
//                case "EntityRef":
//                    this.readEntityRefNode(childNode, configObject);
//                    break;
//                case "ContextInstantRef":
//                    this.readContextInstantRefNode(childNode, configObject);
//                    break;
//
//                default:
//            }
        }
    }

    /**
     * 读取维度定义
     * @param node
     * @param configObject
     */
    private void readObjectDefineNode(Element node, XbrlJsonConfig configObject) {

    }

    /**
     * 读取json数据对象定义系想你
     * @param node
     * @param configObject
     */
    private void readJsonObjectNode(Element node, XbrlJsonConfig configObject) {

        List<Element> childList = node.elements();
        if (childList == null || childList.size() == 0) {
            return ;
        }
        JsonConfigItem jsonConfig = new JsonConfigItem();
        this.fillJsonConfig(jsonConfig, node);
        this.processJsonObject(node, jsonConfig);
        configObject.setJsonConfig(jsonConfig);
    }

    /**
     * 读取节点信息
     * @param parentNode
     * @param parentConfigItem
     */
    private void processJsonObject(Element parentNode, JsonConfigItem parentConfigItem) {

        List<Element> childList = parentNode.elements();
        if (childList == null || childList.size() == 0) {
            return ;
        }
        for (Element item : childList) {
            JsonConfigItem jsonConfig = new JsonConfigItem();
            this.fillJsonConfig(jsonConfig, item);
            parentConfigItem.addChild(jsonConfig);
            // 遍历下级
            this.processJsonObject(item, jsonConfig);
        }
    }

    /**
     *
     * @param jsonConfig
     * @param node
     */
    private void fillJsonConfig(JsonConfigItem jsonConfig, Element node) {

        if (jsonConfig == null || node == null) {
            return ;
        }
        jsonConfig.setContextType(node.attributeValue("contextType"));
        jsonConfig.setControlData(node.attributeValue("controlData"));
        jsonConfig.setDecimals(node.attributeValue("decimals"));
        jsonConfig.setElementName(node.attributeValue("elementName"));
        jsonConfig.setElementNsName(node.attributeValue("elementNsName"));
        jsonConfig.setElementValueType(node.attributeValue("elementValueType"));
        jsonConfig.setFieldName(node.getName());
        jsonConfig.setUnitId(node.attributeValue("unitId"));
    }




    /**
     * 加载命名空间配置信息
     * @param node
     * @param configObject
     */
    private void readNameSpaceNode(Element node, XbrlJsonConfig configObject) {
        List<Element> nameSpaceList = node.elements();
        if (nameSpaceList == null || nameSpaceList.size() == 0) {
            return ;
        }

        Xbrl xbrl = configObject.getXbrlTemp();
        String itemName ;
        String prefix ;
        String uri ;
        for (Element item : nameSpaceList ) {
            itemName = item.getName();
            if (!itemName.equals("nameSpace")) {
                // 非法节点 退出
                continue;
            }

            prefix = item.attributeValue("nameSpacePrefix");
            uri = item.attributeValue("nameSpaceURI");

            // 添加命名空间
            xbrl.addNameSpace(prefix, uri);
        }
    }

    /**
     * 加载SchemaLocation节点
     * @param node
     * @param configObject
     */
    private void readSchemaLocationNode(Element node, XbrlJsonConfig configObject) {

        String value = node.attributeValue("value");
        if (StringUtil.isBlank(value)) {
            return ;
        }

        HashSet<String> set = configObject.getXbrlTemp().getSchemaLocationSet();
        String[] values = value.split(" ");
        for (String item : values) {
            set.add(item);
        }

    }

    /**
     * 加载货币单位节点
     * @param childNode
     * @param configObject
     */
    private void readUnitNode(Element childNode, XbrlJsonConfig configObject) {
//        <unit id ="CNY" measure ="" numerator ="iso4217:CNY" denominator =""/>
        List<Element> unitList = childNode.elements();
        if (unitList == null || unitList.size() == 0) {
            return ;
        }

        String unitId;
        String measure;
        String numerator;
        String denominator;
        for (Element unitNode : unitList) {

            unitId = unitNode.attributeValue("id");
            measure = unitNode.attributeValue("measure");
            numerator = unitNode.attributeValue("numerator");
            denominator = unitNode.attributeValue("denominator");

            if (StringUtil.isBlank(unitId)) {
                return ;
            }
            HashMap<String, Unit> unitMap = configObject.getXbrlTemp().getUnitList();
            if (unitMap.containsKey(unitId)) {
                System.out.println("货币单位编号 "  + unitId + " 数据已经存在，无法重复插入");
                return ;
            }

            Unit unit = new Unit();
            unit.setId(unitId);
            if (!StringUtil.isBlank(measure)) {
                String[] values = measure.split("@");
                for (String value : values) {
                    unit.addMeasure(value);
                }
            }

            if (!StringUtil.isBlank(numerator)) {
                String[] values = numerator.split("@");
                for (String value : values) {
                    unit.addNumerator(value);
                }
            }

            if (!StringUtil.isBlank(denominator)) {
                String[] values = denominator.split("@");
                for (String value : values) {
                    unit.addDenominator(value);
                }
            }
            unitMap.put(unitId, unit);
        }
    }

    /**
     * 读取默认实例文档那个期间
     * @param childNode
     * @param configObject
     */
    private void readContextInstantRefNode(Element childNode, XbrlJsonConfig configObject) {
        String instant = childNode.attributeValue("instant");
        configObject.getXbrlTemp().setInstant(instant);
    }

    /**
     * 读取实体信息
     * @param childNode
     * @param configObject
     */
    private void readEntityRefNode(Element childNode, XbrlJsonConfig configObject) {

        String scheme = childNode.attributeValue("scheme");
        String identifier = childNode.attributeValue("identifier");

        if (StringUtil.isBlank(scheme) || StringUtil.isBlank(identifier)) {
            return ;
        }

        Entity defaultEntity = new Entity();
        defaultEntity.setScheme(scheme);
        defaultEntity.setIdentifier(identifier);

        if (identifier.indexOf("${") >= 0) {
            defaultEntity.setExp(true);
        }
        defaultEntity.setIdentifier(identifier);
        configObject.getXbrlTemp().setDefaultEntity(defaultEntity);

    }

    /**
     * 读取实例文档那个入口文件
     * @param childNode
     * @param configObject
     */
    private void readSchemaRefNode(Element childNode, XbrlJsonConfig configObject) {

        String schemaRef = childNode.attributeValue("schemaRef");
        if (StringUtil.isBlank(schemaRef)) {
            return ;
        }

        SchemaRef sr = new SchemaRef();
        sr.setHref(schemaRef);
        configObject.getXbrlTemp().setSchemaRef(sr);
    }

}





























